import { BaseService } from '@/core/base.service';
import { BaseQueryDto, PublisherUserFollowsQueryDto } from '@/dtos';
import { Injectable } from '@nestjs/common';
import { Prisma, Publisher } from '@prisma/client';

@Injectable()
export class PublisherService extends BaseService {
  async query({
    params,
    sort,
  }: BaseQueryDto<Prisma.PublisherWhereUniqueInput>) {
    const { current = 1, pageSize = 20, keyword, ...where } = params;

    let sql = `
      SELECT #{fields} FROM Publisher AS t
      WHERE t.isDeleted = false
        ${!!where.name ? `AND t.name LIKE '%${where.name}%'` : ''}
    `;

    const [{ count }] = await this.prisma.$queryRawUnsafe<[{ count: number }]>(
      sql.replace('#{fields}', 'COUNT(t.id) AS count'),
    );

    const list = await this.prisma.$queryRawUnsafe<Publisher[]>(
      `${sql.replace('#{fields}', 't.id, t.name, t.logo, t.labels, t.detail')}
      ORDER BY ${
        !!sort && Object.keys(sort).length > 0
          ? Object.entries(sort)
              .map(([k, v]) => `t.${k} ${v === 'descend' ? 'DESC' : 'ASC'}`)
              .join(',')
          : 't.createdAt DESC'
      }
      LIMIT ${pageSize} 
      OFFSET ${(current - 1) * pageSize}
      `,
    );

    const total = count ? Number(count) : 0;
    const totalPage = Math.ceil(total / pageSize);
    const hasMore = current < totalPage;

    return {
      total,
      totalPage,
      hasMore,
      current,
      pageSize,
      list,
    };
  }

  async findOne(
    where: Prisma.PublisherWhereUniqueInput,
    select?: Prisma.PublisherSelect,
  ): Promise<Publisher | null> {
    return this.prisma.publisher.findUnique({
      where,
      select,
    });
  }

  async create(data: Prisma.PublisherCreateInput): Promise<Publisher> {
    return this.prisma.publisher.create({
      data,
    });
  }

  async update(params: {
    where: Prisma.PublisherWhereUniqueInput;
    data: Prisma.PublisherUpdateInput;
  }): Promise<Publisher> {
    const { where, data } = params;
    return this.prisma.publisher.update({
      where,
      data,
    });
  }

  async remove(where: Prisma.PublisherWhereUniqueInput): Promise<Publisher> {
    return this.prisma.publisher.update({
      where,
      data: {
        isDeleted: true,
      },
    });
  }

  async getUserFollows(
    userId: number,
    { params, sort }: PublisherUserFollowsQueryDto,
  ) {
    const { current = 1, pageSize = 20, keyword, ...where } = params;

    let sql = `
      SELECT #{fields} FROM UserFollowPublisher AS t
      LEFT JOIN Publisher AS p ON t.publisherId = p.id
      WHERE t.userId = ${userId}
    `;

    const [{ count }] = await this.prisma.$queryRawUnsafe<[{ count: number }]>(
      sql.replace('#{fields}', 'COUNT(p.id) AS count'),
    );

    const list = await this.prisma.$queryRawUnsafe<any[]>(
      `${sql.replace(
        '#{fields}',
        `
        p.id, p.name, p.logo,
        (SELECT COUNT(u.userId) FROM UserFollowPublisher AS u WHERE publisherId = p.id) AS followCount
      `,
      )}
      ORDER BY t.createdAt DESC
      LIMIT ${pageSize} 
      OFFSET ${(current - 1) * pageSize}
      `,
    );

    const total = count ? Number(count) : 0;
    const totalPage = Math.ceil(total / pageSize);
    const hasMore = current < totalPage;

    return {
      total,
      totalPage,
      hasMore,
      current,
      pageSize,
      list: list.map((item) => ({
        ...item,
        followCount: Number(item.followCount),
      })),
    };
  }
}
